package cloud.keveri.gateway.core;

import cloud.keveri.gateway.config.api.listener.RulesChangeSubscriber;
import cloud.keveri.gateway.dto.IDefinitionDynamicManager;
import cloud.keveri.gateway.dto.Rule;
import cloud.keveri.gateway.dto.ServiceDefinition;
import cloud.keveri.gateway.dto.ServiceInstance;
import cn.hutool.core.util.StrUtil;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 路由规则管理器
 * <p>
 * 作者：沈自在
 **/
@Component
public class DefinitionDefinitionManager implements RulesChangeSubscriber, IDefinitionDynamicManager {
    /**
     * Key 为 RuleId
     */
    private ConcurrentHashMap<String, Rule> ruleMap = new ConcurrentHashMap<>();

    /**
     * Key 为 Path
     */
    private ConcurrentHashMap<String, Rule> pathRuleMap = new ConcurrentHashMap<>();
    /**
     * Key 为服务名
     */
    private ConcurrentHashMap<String, List<Rule>> serviceRuleMap = new ConcurrentHashMap<>();

    /**
     * 服务的定义集合
     */
    private final ConcurrentHashMap<String, ServiceDefinition> serviceDefinitionMap = new ConcurrentHashMap<>();

    /**
     *
     */
    private final ConcurrentHashMap<String, Set<ServiceInstance>> serviceInstanceMap = new ConcurrentHashMap<>();

    @Override
    public void onRulesChange(List<Rule> ruleList) {
        // 1. 初始化
        ConcurrentHashMap<String, Rule> newRuleMap = new ConcurrentHashMap<>();
        ConcurrentHashMap<String, Rule> newPathMap = new ConcurrentHashMap<>();
        ConcurrentHashMap<String, List<Rule>> newServiceMap = new ConcurrentHashMap<>();

        // 2. 循环处理
        for (Rule rule : ruleList) {
            newRuleMap.put(rule.getId(), rule);
            String serviceId = rule.getServiceId();
            newServiceMap.computeIfAbsent(serviceId, k -> new ArrayList<>()).add(rule);

            List<String> paths = rule.getPaths();
            for (String path : paths) {
                String key = serviceId + "." + path;
                newPathMap.put(key, rule);
            }
        }

        // 3. 保存
        ruleMap = newRuleMap;
        pathRuleMap = newPathMap;
        serviceRuleMap = newServiceMap;
    }

    /**
     *
     */
    public void addServiceInstance(String uniqueId, Set<ServiceInstance> serviceInstanceSet) {
        serviceInstanceMap.put(uniqueId, serviceInstanceSet);
    }
    /**
     *
     */
    public void putServiceDefinition(String uniqueId,
                                     ServiceDefinition serviceDefinition) {
        serviceDefinitionMap.put(uniqueId, serviceDefinition);;
    }

    /**
     *
     */
    @Override
    public ServiceDefinition acquireServiceDefinition(String uniqueId) {
        return serviceDefinitionMap.get(uniqueId);
    }

    /**
     *
     */
    @Override
    public ServiceDefinition acquireServiceDefinitionWithPath(String path) {
        if (StrUtil.isBlank(path)) {
            return null;
        }
        for (ServiceDefinition definition : serviceDefinitionMap.values()) {
            String definitionPath = definition.getPatternPath();
            if (StrUtil.isNotBlank(definitionPath) && path.startsWith(definitionPath)) {
                return definition;
            }
        }
        return null;
    }

    /**
     *
     */
    @Override
    public Set<ServiceInstance> acquireServiceInstanceWithUniqueId(String uniqueId) {
        return serviceInstanceMap.get(uniqueId);
    }

    /**
     *
     */
    @Override
    public Rule acquireRuleWithPath(String key) {
        return pathRuleMap.get(key);
    }

    /**
     *
     */
    @Override
    public List<Rule> acquireRulesWithServiceId(String serviceId) {
        return serviceRuleMap.get(serviceId);
    }
}
